home *** CD-ROM | disk | FTP | other *** search
/ Amiga Collections: Camelot / Camelot 043 (1989-06)(Swedish User Group of Amiga)(SE)(PD)[WB].zip / Camelot 043 (1989-06)(Swedish User Group of Amiga)(SE)(PD)[WB].adf / Glib / glib.c < prev    next >
C/C++ Source or Header  |  1989-03-16  |  29KB  |  1,473 lines

  1. /*
  2.  * GLIB - a Generic LIBrarian and editor for synths
  3.  */
  4.  
  5. #include "glib.h"
  6. #include <ctype.h>
  7.  
  8. char *Reason = "";
  9.  
  10. int Currrow = 0;    /* at top of screen, for messages */
  11. int Libbank = 0;    /* from 0 to LIBBANKS-1, is the current library bank*/
  12. int Nsynths = 0;
  13.  
  14. char *Currdata;
  15. char *Yankdata;        /* current 'yank' buffer (middle of screen) */
  16.  
  17. struct peredinfo *PE;    /* array of per-editor miscellany */
  18.  
  19. char Buff[BUFSIZ];
  20. int Redraw = 0;        /* if non-0, edit screen is completely redrawn. */
  21.             /* parameter functions can make use of this. */
  22. int Changed = 0;
  23.  
  24. /* All the global values below are set as appropriate for the */
  25. /* synthesizer currently being dealt with. */
  26.  
  27. int Nvoices = 0;
  28. int Voicesize =0;
  29. int Namesize = 0;
  30. int Libindex;        /* from 0 to Nvoices-1 */
  31. int Synindex;        /* from 0 to Nvoices-1 */
  32. int Channel;
  33. int Editrow;        /* from 0 to NUMONSCREEN-1 */
  34. int Editcol;        /* 0==synth, 1==library */
  35. char *Libdata;        /* current library data (includes all LIBBANKS) */
  36.             /* ie. the stuff on the right side of the screen */
  37. char *Syndata;        /* current synth data (1 bank), ie. the left side */
  38. struct paraminfo *P;    /* list of parameter info */
  39. struct labelinfo *L;    /* arbitrary screen labels for edit screen */
  40. char *Synthname;
  41.  
  42. int (*Sendedit)();    /* function to send parameters to synth's edit buffer*/
  43. int (*Datain)();    /* convert data from file-storage format to the */
  44.             /* format stored in the P[] parameter array (p_val) */
  45. int (*Dataout)();    /* reverse of Datain */
  46. int (*Sendone)();    /* function to send one (permanent) voice to synth */
  47. int (*Sendbulk)();    /* function to send bulk dump to synth */
  48. int (*Getbulk)();    /* reverse of Sendbulk */
  49. char *(*Nameof)();    /* pulls voice name out of file-storage data */
  50. int (*Setnameof)();    /* reverse of Nameof */
  51. char *(*Numof)();    /* convert voice number to on-screen text */
  52. int (*Cvtnum)();    /* convert visible voice number to std. format */
  53. int (*Cvtanum)();    /* convert alphanumeric voice number to std. format */
  54.             /* should never define both Cvtnum and Cvtanum */
  55. main()
  56. {
  57.     int n;
  58.  
  59.     hello();
  60.     windinit();
  61.     initstuff();
  62.  
  63.     if ( Nsynths == 0 )
  64.         windstr("Hey, the E array is empty?");
  65.     else if ( Nsynths == 1 ) {
  66.         /* If there's only 1 synth, don't bother asking */
  67.         setedit(0);
  68.         libinteract();
  69.     }
  70.     else {
  71.         while ( (n=choosesynth()) >= 0 ) {
  72.             setedit(n);
  73.             libinteract();
  74.             unsetedit(n);
  75.         }
  76.     }
  77.     bye();
  78. }
  79.  
  80. /* choose a synth, returning its position in the E array */
  81. choosesynth()
  82. {
  83.     int n, pick;
  84.  
  85.     retry:
  86.     flushconsole();
  87.     windclear();
  88.     windgoto(2,18);
  89.     windstr("GLIB - A Generic Librarian/Editor");
  90.  
  91.     for ( n=1; n<=Nsynths; n++ )
  92.         libchoice(n);
  93.  
  94.     windgoto(10+n,16);
  95.     windstr("Choose your synth (or 'q' to quit) --> ");
  96.     windrefresh();
  97.     pick = mouseorkey();
  98.     if ( pick == 'q' || pick == EOF )
  99.         return(-1);
  100.     if ( pick != MOUSE )
  101.         pick = pick - '0';
  102.     else {
  103.         int row, col;
  104.         getmouse(&row,&col);
  105.         /* wait until mouse goes down */
  106.         while ( statmouse() > 0 )
  107.             ;
  108.         pick = row - 6; 
  109.     }
  110.     if ( pick < 1 || pick > Nsynths )
  111.         goto retry;
  112.     return(pick-1);
  113. }
  114.  
  115. libchoice(n)
  116. {
  117.     windgoto(6+n,27);
  118.     sprintf(Buff,"%d  -  %s",n,E[n-1].ed_name);
  119.     windstr(Buff);
  120. }
  121.  
  122. initstuff()
  123. {
  124.     int n, banksize, maxvsize = 0;
  125.     char *p;
  126.     
  127.     for ( n=0; E[n].ed_name != NULL; n++ ) {
  128.         if ( maxvsize < E[n].ed_vsize )
  129.             maxvsize = E[n].ed_vsize;
  130.     }
  131.     Nsynths = n;
  132.     Currdata = alloc( maxvsize );
  133.  
  134.     /* allocate an array of peredinfo structs */
  135.     PE =(struct peredinfo *)alloc((int)(Nsynths*sizeof(struct peredinfo)));
  136.     for ( n=0; n<Nsynths; n++ ) {
  137.         banksize =  E[n].ed_nvoices * E[n].ed_vsize;
  138.         p = PE[n].ed_libdata = alloc( LIBBANKS * banksize );
  139.         clrdata(p,LIBBANKS*banksize);
  140.         p = PE[n].ed_syndata = alloc( banksize );
  141.         clrdata(p,banksize);
  142.         p = PE[n].ed_yankdata = alloc( E[n].ed_vsize );
  143.         clrdata(p,E[n].ed_vsize);
  144.         PE[n].ed_libindex = 0;
  145.         PE[n].ed_synindex = 0;
  146.         PE[n].ed_channel = 1;
  147.         PE[n].ed_erow = 0;
  148.         PE[n].ed_ecol = 0;
  149.     }
  150. }
  151.  
  152. clrdata(data,size)
  153. char *data;
  154. {
  155.     register char *p = data, *endp = data+size;
  156.  
  157.     while ( p<endp )
  158.         *p++ = 0;
  159. }
  160.  
  161. setedit(n)
  162. {
  163.     Synthname = E[n].ed_name;
  164.     Datain = E[n].ed_din;
  165.     Dataout = E[n].ed_dout;
  166.     Nvoices = E[n].ed_nvoices;
  167.     Sendedit = E[n].ed_sedit;
  168.     Sendone = E[n].ed_sone;
  169.     Sendbulk = E[n].ed_sbulk;
  170.     Getbulk = E[n].ed_gbulk;
  171.     Nameof = E[n].ed_nof;
  172.     Numof = E[n].ed_numof;
  173.     Cvtnum = E[n].ed_cvtnum;
  174.     Cvtanum = E[n].ed_cvtanum;
  175.     Setnameof = E[n].ed_snof;
  176.     Voicesize = E[n].ed_vsize;
  177.     Namesize = E[n].ed_nsize;
  178.     Libdata = PE[n].ed_libdata;
  179.     Syndata = PE[n].ed_syndata;
  180.     Yankdata = PE[n].ed_yankdata;
  181.     Libindex = PE[n].ed_libindex;
  182.     Synindex = PE[n].ed_synindex;
  183.     Channel = PE[n].ed_channel;
  184.     Editrow = PE[n].ed_erow;
  185.     Editcol = PE[n].ed_ecol;
  186.     clrdata(Currdata,Voicesize);
  187.     P = E[n].ed_params;
  188.     L = E[n].ed_labels;
  189. }
  190.  
  191. unsetedit(n)
  192. {
  193.     int k;
  194.  
  195.     PE[n].ed_libindex = Libindex;
  196.     PE[n].ed_synindex = Synindex;
  197.     PE[n].ed_channel = Channel;
  198.     PE[n].ed_erow = Editrow;
  199.     PE[n].ed_ecol = Editcol;
  200.     for ( k=0; k<Voicesize; k++ )
  201.         PE[n].ed_yankdata[k] = Yankdata[k];
  202. }
  203.  
  204. /* template - show the boxes and such on the main library screen */
  205. template()
  206. {
  207.     int n, k, r;
  208.  
  209.     r = FIRSTROW-1;
  210.     sprintf(Buff,"%s Voices",Synthname);
  211.     n = 13 - strlen(Buff)/2;    /* center it */
  212.     windgoto(r,n<0?0:n);
  213.     windstr(Buff);
  214.     r++;
  215.     windgoto(r,0);
  216.     for ( n=0; n<26; n++ )
  217.         windputc('=');
  218.     windgoto(r,52);
  219.     for ( n=0; n<26; n++ )
  220.         windputc('=');
  221.     for ( n=r+1; n<(r+13); n++ ) {
  222.         windgoto(n,0);
  223.         windputc('|');
  224.         windgoto(n,6);
  225.         windputc('|');
  226.         windgoto(n,25);
  227.         windputc('|');
  228.  
  229.         k=52;
  230.         windgoto(n,k);
  231.         windputc('|');
  232.         windgoto(n,k+6);
  233.         windputc('|');
  234.         windgoto(n,k+25);
  235.         windputc('|');
  236.     }
  237.     windgoto(r+13,0);
  238.     for ( n=0; n<26; n++ )
  239.         windputc('=');
  240.     windgoto(r+13,52);
  241.     for ( n=0; n<26; n++ )
  242.         windputc('=');
  243.  
  244.     windgoto(YANKROW-2,YANKCOL);
  245.     windstr("  Yank Buffer");
  246.     windgoto(YANKROW-1,YANKCOL);
  247.     windstr(" ------------- ");
  248.     windgoto(YANKROW,YANKCOL);
  249.     windstr("               ");
  250.     windgoto(YANKROW+1,YANKCOL);
  251.     windstr(" ------------- ");
  252.     windrefresh();
  253. }
  254.  
  255. /* clear the message area */
  256. clearmess()
  257. {
  258.     int n;
  259.     for(n=1;n<(FIRSTROW-1);n++)
  260.         winderaserow(n);
  261.     Currrow = 0;
  262. }
  263.  
  264. /* set the current voice (ie. the synth's edit buffer) to the indicated */
  265. /* voice.  c==0 is the synth (left) side, c==1 is the library (right) side. */
  266. editto(r,c)
  267. {
  268.     int voicenum;
  269.  
  270.     /* Clear the existing '*' */
  271.     editchar(' ',Editrow,Editcol);
  272.     editchar('*',Editrow=r,Editcol=c);
  273.     if ( Editcol==0 ) {
  274.         /* we're on the synth side */
  275.         voicenum = Editrow+Synindex;
  276.         tocurrent(Syndata,voicenum);
  277.     }
  278.     else {
  279.         /* we're on the lib side */
  280.         voicenum = Editrow+Libindex;
  281.         tocurrent(bankvoice(0),voicenum);
  282.     }
  283. }
  284.  
  285. editchar(ec,r,c)
  286. {
  287.     r = r + FIRSTROW + 1;
  288.     if ( c == 0 )
  289.         c = LEFTSIDE-1;
  290.     else
  291.         c = RIGHTSIDE-1;
  292.     windgoto(r,c);
  293.     windputc(ec);
  294.     windrefresh();
  295. }
  296.  
  297. /* control interaction on the main library bank screen */
  298. libinteract()
  299. {
  300.     int c, n, swap, voicenum, maxindex;
  301.     char *p, *data;
  302.  
  303.     flushmidi();
  304.     drawall();
  305.     for ( ;; ) {
  306.         Currrow = 0;
  307.         winderaserow(Currrow);
  308.         windgoto(Currrow,0);
  309.         windstr("Command --> ");
  310.         windrefresh();
  311.         
  312.         c = mouseorkey();
  313.         if ( c == MOUSE ) {
  314.             libmouse();
  315.             continue;
  316.         }
  317.  
  318.         if ( isprint(c) )
  319.             windputc(c);
  320.         clearmess();
  321.         switch ( c ) {
  322.         case ' ':
  323.             playnote(1);
  324.             break;
  325.         case '\n':
  326. #ifndef macintosh
  327.         case '\r':
  328. #endif
  329.             /* ignore */
  330.             break;
  331.         case EOF:
  332.         case 'q':
  333.             return;
  334.         case CH_REDRAW:
  335.             drawall();
  336.             break;
  337.         case 's':
  338.         case 'p':
  339.             swap = (c=='s')?1:0;
  340.             if ( Editcol==0 )
  341.                 tosyn(Synindex+Editrow,Yankdata,swap);
  342.             else
  343.                 tolib(Libindex+Editrow,Yankdata,swap);
  344.             updatedisplay();
  345.             pryankname();
  346.             break;
  347.         case 'y':
  348.             for(n=0;n<Voicesize;n++)
  349.                 Yankdata[n] = Currdata[n];
  350.             pryankname();
  351.             break;
  352.         case '?':
  353.             helpmessage();
  354.             break;
  355.         case SCR_DOWN:
  356.             maxindex = Nvoices - NUMONSCREEN;
  357.             if ( Editcol==0 ) {
  358.                 /* we're on the synth side */
  359.                 if ( (Synindex+=NUMONSCREEN/2) > maxindex )
  360.                     Synindex = maxindex;
  361.             }
  362.             else {
  363.                 /* we're on the lib side */
  364.                 if ( (Libindex+=NUMONSCREEN/2) > maxindex )
  365.                     Libindex = maxindex;
  366.             }
  367.             updatedisplay();
  368.             break;
  369.         case SCR_UP:
  370.             if ( Editcol==0 ) {
  371.                 /* we're on the synth side */
  372.                 if ( (Synindex-=NUMONSCREEN/2) < 0 )
  373.                     Synindex = 0;
  374.             }
  375.             else {
  376.                 /* we're on the lib side */
  377.                 if ( (Libindex-=NUMONSCREEN/2) < 0 )
  378.                     Libindex = 0;
  379.             }
  380.             updatedisplay();
  381.             break;
  382.         case '\033':
  383.         case '`':
  384.             allnotesoff();
  385.             break;
  386.         case 't':
  387.             transcmd();
  388.             break;
  389.         case 'd':    /* download from synth to display */
  390.             clrdata(Syndata,Nvoices*Voicesize);
  391.             if ( readsynth(Syndata) == 0 )
  392.                 syntodisplay(Synindex=0);
  393.             break;
  394.         case 'u':    /* upload TO synth */
  395.             if ( Editcol==0 ) {
  396.                 voicenum = Editrow+Synindex;
  397.                 data = &(VOICEBYTE(Syndata,voicenum,0));
  398.             }
  399.             else
  400.                 data = bankvoice(Editrow+Libindex);
  401.             upload(data);
  402.             break;
  403.         case 'r':
  404.             readall();
  405.             break;
  406.         case 'w':
  407.             writeall();
  408.             break;
  409.         case 'c':
  410.             setchan();
  411.             break;
  412.         case 'b':
  413.             /* cycle through banks, from 0 to LIBBANKS-1 */
  414.             if ( ++Libbank >= LIBBANKS )
  415.                 Libbank = 0;
  416.             libtodisplay(Libindex);
  417.             updatedisplay();
  418.             break;
  419.         case 'e':
  420.             p = (*Nameof)(Currdata);
  421.             if ( Editcol==0 ) {
  422.                 voicenum = Editrow+Synindex;
  423.                 data = &(VOICEBYTE(Syndata,voicenum,0));
  424.                 editdata(p,data);
  425.                 windclear();
  426.                 /* Update Currdata */
  427.                 for ( n=0; n<Voicesize; n++ )
  428.                     Currdata[n] = VOICEBYTE(Syndata,voicenum,n);
  429.             }
  430.             else {
  431.                 data = bankvoice(Editrow+Libindex);
  432.                 editdata(p,data);
  433.             }
  434.             drawall();
  435.             break;
  436.         case 'g': /* goto a specific voice */
  437.             do_goto();
  438.             break;
  439.         case CH_LEFT:
  440.             if ( Editcol==1 )
  441.                 editto(Editrow,0);
  442.             break;
  443.         case CH_DOWN:
  444.             if ( Editrow < (NUMONSCREEN-1) )
  445.                 editto(Editrow+1,Editcol);
  446.             else {
  447.                 /* we're at the bottom, so try to scroll */
  448.                 if ( Editcol==0 ) {
  449.                     /* we're on the synth side */
  450.                     if (Synindex<(Nvoices-NUMONSCREEN))
  451.                         Synindex++;
  452.                 }
  453.                 else {
  454.                     /* we're on the lib side */
  455.                     if (Libindex<(Nvoices-NUMONSCREEN))
  456.                         Libindex++;
  457.                 }
  458.                 updatedisplay();
  459.             }
  460.             break;
  461.         case CH_UP:
  462.             if ( Editrow>0 )
  463.                 editto(Editrow-1,Editcol);
  464.             else {
  465.                 /* we're at the top, so try to scroll */
  466.                 if ( Editcol==0 ) {
  467.                     /* we're on the synth side */
  468.                     if (Synindex>0)
  469.                         Synindex--;
  470.                 }
  471.                 else {
  472.                     /* we're on the lib side */
  473.                     if (Libindex>0)
  474.                         Libindex--;
  475.                 }
  476.                 updatedisplay();
  477.             }    
  478.             break;
  479.         case CH_RIGHT:
  480.             if ( Editcol==0 )
  481.                 editto(Editrow,1);
  482.             break;
  483.         case 'f':
  484.             filelist();
  485.             break;
  486.         default:
  487.             message("Unrecognized command!  Press '?' for help.");
  488.             break;
  489.         }
  490.     }
  491. }
  492.  
  493. filelist()
  494. {
  495.     char *p, *q, buff[BUFSIZ];
  496.     int n, ninline = 0, nprinted = 0;
  497.  
  498.     clearmess();
  499.     Currrow = -1;    /* To start message on top line */
  500.     openls();
  501.     message("Files in current directory:");
  502.     strcpy(buff,"  ");
  503.     while ( (p=nextls()) != NULL ) {
  504.         /* add the next file to the line being constructed */
  505.         q = &buff[strlen(buff)];
  506.         strcpy(q,p);
  507.         q += (n=strlen(p));
  508.         while ( n++ < 15 )
  509.             *q++ = ' ';
  510.         *q = '\0';
  511.         if ( ninline++ > 3 ) {
  512.             message(buff);
  513.             if ( nprinted++ > 4 ) {
  514.                 message("Press any key to continue ...");
  515.                 getconsole();
  516.                 clearmess();
  517.                 nprinted = 0;
  518.             }
  519.             strcpy(buff,"  ");
  520.             ninline = 0;
  521.         }
  522.     }
  523.     if ( ninline > 0 )
  524.         message(buff);
  525.     closels();
  526. }
  527.  
  528. libmouse()
  529. {
  530.     int row, col;
  531.  
  532.     getmouse(&row,&col);
  533.     if ( row <= FIRSTROW || row > FIRSTROW+NUMONSCREEN+1 )
  534.         goto getout;
  535.     if ( col < Cols/2 )
  536.         col = 0;
  537.     else
  538.         col = 1;
  539.     row = row - FIRSTROW - 1;
  540.     editto(row,col);
  541. getout:
  542.     /* wait until mouse button is released */
  543.     while ( statmouse() > 0 )
  544.         ;
  545. }
  546.  
  547. do_goto()
  548. {
  549.     int n, r, maxindex, new_ecol;
  550.     char sbuf[100], *sp;
  551.     
  552.     message("");
  553.     message("Where to? ");
  554.     windgets(sbuf);
  555.     
  556.     sp = sbuf;
  557.     switch(*sp++) {
  558.       case 's': /* synth side */
  559.         new_ecol = 0;
  560.         break;
  561.       case 'l': /* library side */
  562.         new_ecol = 1;
  563.         break;
  564.       default: /* no change in side */
  565.           new_ecol = Editcol;
  566.         sp--;    /* but don't trash the first character */
  567.         break;
  568.     }
  569.     
  570.     clearmess();
  571.     r = sscanf(sp, "%d", &n); /* this may fail - we handle it later */
  572.     if(Cvtnum != NULL) { /* convert to internal format if needed */
  573.         n = (*Cvtnum)(n) + 1; /* we are 1-based for user input */
  574.     }
  575.     if (Cvtanum != NULL) { /* convert using alphanumeric voice number */
  576.         n = (*Cvtanum)(sp) + 1;
  577.     }
  578.     if(r != 1) {
  579.         message("type one of: sn, ln, or n");
  580.         message("  s = synth side (literal character 's')");
  581.         message("  l = library side (literal character 'l')");
  582.         message("  n = voice number to select (an integer)");
  583.         return;
  584.     }
  585.     if(n <= 0 || n > Nvoices) { /* 1-based */
  586.         message("Bad voice number!");
  587.         return;
  588.     }
  589.     
  590.     /* it can be done.  nuke the old '*' and change columes (if needed) */
  591.     editchar(' ', Editrow, Editcol);
  592.     Editcol = new_ecol;
  593.     
  594.     /* try to center it */
  595.     maxindex = Nvoices - NUMONSCREEN;
  596.     if(Editcol == 0) {
  597.         Synindex = (n - 1) - NUMONSCREEN/2; /* 0-based */
  598.         if(Synindex < 0) { /* impossible to center */
  599.             Synindex = 0; /* so do your best */
  600.         } else if(Synindex > maxindex) {
  601.             Synindex = maxindex;
  602.         }
  603.         Editrow = (n - 1) - Synindex; /* and put a '*' on it */
  604.     } else {
  605.         Libindex = (n - 1) - NUMONSCREEN/2; /* 0-based */
  606.         if(Libindex < 0) {
  607.             Libindex = 0;
  608.         } else if(Libindex > maxindex) {
  609.             Libindex = maxindex;
  610.         }
  611.         Editrow = (n - 1) - Libindex;
  612.     }
  613.     
  614.     updatedisplay(); /* do the real work */
  615.     return;
  616. }
  617.  
  618. upload(data)
  619. char *data;
  620. {
  621.     int c, n;
  622.     char num[16];
  623.  
  624.     message("");
  625.     message("Upload TO synth:");
  626.     message("                 c - current voice");
  627.     message("                 a - ALL voices");
  628.     message("Choose --> ");
  629.     c = getconsole();
  630.     if ( c == 'c' ) {
  631.         clearmess();
  632.         if ( Sendone == NULL ) {
  633.             message("Single voices can't be sent to that synth!");
  634.             return;
  635.         }
  636.         message("What voice number to you want to send it TO? --> ");
  637.         windgets(num);
  638.         clearmess();
  639.         n = atoi(num);
  640.         if(Cvtnum != NULL) { /* convert to internal format if needed */
  641.             n = (*Cvtnum)(n) + 1; /* we are 1-based for user input */
  642.         }
  643.         if (Cvtanum != NULL) { /* howzabout alphanumeric format? */
  644.             n = (*Cvtanum)(num) + 1;
  645.         }
  646.         if ( n > 0 && n <= Nvoices ) {
  647.             if ( (*Sendone)(n-1,data) != 0 ) { /* 0-based on calls -SAF */
  648.                 message("Unable to write data to synth!");
  649.                 sprintf(Buff,"Reason: %s",Reason);
  650.                 message(Buff);
  651.             }
  652.         } else {
  653.             message("Bad voice number!");
  654.         }
  655.     }
  656.     else if ( c == 'a' ) {
  657.         clearmess();
  658.         if ( Sendbulk != NULL )
  659.             (*Sendbulk)(Syndata);
  660.         else {
  661.             for ( n=0; n<Nvoices; n++ ) {
  662.                 if ( (*Sendone)(n, &(VOICEBYTE(Syndata,n,0)) ) != 0 ) {
  663.                     message("Unable to write data to synth!");
  664.                     sprintf(Buff,"Reason: %s",Reason);
  665.                     message(Buff);
  666.                     break;
  667.                 }
  668.             }
  669.         }
  670.         /* clearmess(); */
  671.     }
  672.     else {
  673.         clearmess();
  674.         message("Bad choice!");
  675.     }
  676. }
  677.  
  678. helpmessage()
  679. {
  680. clearmess();
  681. sprintf(Buff,"%s,%s,%s,%s - move around              e - edit current voice",
  682.     STR_LEFT,STR_DOWN,STR_UP,STR_RIGHT);
  683. message(Buff);
  684. message("r - read voices from a file        y - yank into buffer");
  685. message("w - write voices to a file         p - put from buffer");
  686. message("b - cycle through library banks    s - swap current voice with yank buffer");
  687. message("t - transfer all voices            f - list files in current directory");
  688. message("d - download voices from synth     c - set MIDI channel");
  689. message("u - upload voices to synth         g - 'goto' form of moving around");
  690. message("q - quit                           <space> - play a note");
  691. }
  692.  
  693. updatedisplay()
  694. {
  695.     if ( Editcol==0 ) {
  696.         /* we're on the synth side */
  697.         syntodisplay(Synindex);
  698.         editto(Editrow,Editcol);
  699.     }
  700.     else {
  701.         /* we're on the lib side */
  702.         libtodisplay(Libindex);
  703.         editto(Editrow,Editcol);
  704.     }
  705. }
  706.  
  707. pryankname()
  708. {
  709.     char ybuff[33];
  710.     char *p;
  711.  
  712.     windgoto(YANKROW,YANKCOL-4);
  713.     windstr("                    ");
  714.     strcpy(ybuff,(*Nameof)(Yankdata));
  715.     /* take off trailing blanks */
  716.     p = ybuff + strlen(ybuff) - 1;
  717.     while ( p>ybuff && *p == ' ' )
  718.         *p-- = '\0';
  719.     windgoto(YANKROW,YANKCOL+7-strlen(ybuff)/2);
  720.     windstr(ybuff);
  721.     windrefresh();
  722. }
  723.  
  724. transcmd()
  725. {
  726.     int fromc;
  727.  
  728.     message("");
  729.     message("Transfer ALL voices:");
  730.     message("                       1:   <<-----   from library bank to synth bank");
  731.     message("                       2:   ----->>   from synth bank to library bank");
  732.     message("1 or 2 --> ");
  733.     fromc = getconsole();
  734.     windputc(fromc);
  735.     if ( fromc!='1' && fromc!='2' ) {
  736.         clearmess();
  737.         return;
  738.     }
  739.     switch ( fromc ) {
  740.     case '1':
  741.         copyall(bankvoice(0),Syndata);
  742.         syntodisplay(Synindex);
  743.         clearmess();
  744.         message("Use the 'u'pload command to actually send the synth bank voices to the synth.");
  745.         break;
  746.     case '2':
  747.         copyall(Syndata,bankvoice(0));
  748.         libtodisplay(Libindex);
  749.         clearmess();
  750.         break;
  751.     }
  752. }
  753.  
  754. copyall(fromdata,todata)
  755. char *fromdata;
  756. char *todata;
  757. {
  758.     int n, v;
  759.  
  760.     for ( v=0; v<Nvoices; v++ )
  761.         for ( n=0; n<Voicesize; n++ )
  762.             VOICEBYTE(todata,v,n) = VOICEBYTE(fromdata,v,n);
  763. }
  764.  
  765. message(s)
  766. char *s;
  767. {
  768.     windgoto(++Currrow,0);
  769.     windstr(s);
  770.     windrefresh();
  771. }
  772.  
  773. setchan()
  774. {
  775.     int c;
  776.  
  777.     message("New MIDI channel --> ");
  778.     windgets(Buff);
  779.     if ( (c=atoi(Buff)) <= 0 || c > 16 ) {
  780.         clearmess();
  781.         message("Invalid channel!");
  782.     }
  783.     else {
  784.         clearmess();
  785.         Channel = c;
  786.         showchan();
  787.     }
  788. }
  789.  
  790. showchan()
  791. {
  792.     windgoto(20,31);
  793.     windstr("MIDI Channel: ");
  794.     sprintf(Buff,"%d ",Channel);
  795.     windstr(Buff);
  796.     windrefresh();
  797. }
  798.  
  799. /* read data from a file, filling the current library bank. */
  800. readall()
  801. {
  802.     char fname[100];
  803.     FILE *f;
  804.     int v, n, r;
  805.  
  806.     message("File name --> ");
  807.     windgets(fname);
  808.     OPENBINFILE(f,fname,"r");
  809.     if (f == NULL ) {
  810.         sprintf(Buff,"Can't open '%s'!",fname);
  811.         message(Buff);
  812.         return;
  813.     }
  814.     /* Check the first byte.  If it's 0xdd, then the format is mine. */
  815.     /* If the first byte is 0-31, it's also mine. */
  816.     n = (getc(f) & 0xff);
  817.     if ( n == 0xdd || n<=31 ) {
  818.         if ( n <= 31 )
  819.             ungetc(n,f);
  820.         /* This is my format, just raw data. */
  821.         for ( v=0; v<Nvoices; v++ ) {
  822.             char *p = bankvoice(v);
  823.             for ( n=0; n<Voicesize; n++ )
  824.                 *p++ = getc(f);
  825.         }
  826.         r = 0;
  827.     }
  828.     /* code for other formats would go here */
  829.     else {
  830.         message("Unknown file format");
  831.         r = 1;
  832.     }
  833.     fclose(f);
  834.     if ( r==0 ) {
  835.         libtodisplay(Libindex=0);
  836.         clearmess();
  837.     }
  838. }
  839.  
  840. /* write current library bank to a file */
  841. writeall()
  842. {
  843.     char fname[100];
  844.     FILE *f;
  845.     int v, n;
  846.  
  847.     message("File name --> ");
  848.     windgets(fname);
  849.     OPENBINFILE(f,fname,"w");
  850.     if ( f == NULL ) {
  851.         sprintf(Buff,"Can't open '%s'!",fname);
  852.         message(Buff);
  853.         return;
  854.     }
  855.     putc(0xdd,f);    /* magic byte to identify my format */
  856.     for ( v=0; v<Nvoices; v++ ) {
  857.         char *p = bankvoice(v);
  858.         for ( n=0; n<Voicesize; n++ )
  859.             putc(*p++,f);
  860.     }
  861.     fclose(f);
  862.     clearmess();
  863. }
  864.  
  865. /* draw main library/synth voice bank screen */
  866. drawall()
  867. {
  868.     windclear();
  869.     template();
  870.     libtodisplay(Libindex);
  871.     syntodisplay(Synindex);
  872.     editto(Editrow,Editcol);
  873.     pryankname();
  874.     showchan();
  875. }
  876.  
  877. /*
  878.  * tosyn
  879.  *
  880.  * Store the given 'data' in in voice 'voicenum' (both in Syndata
  881.  * AND on the synth itself).  If swap is non-zero, the voice is swapped
  882.  * with the current voice in Syndata.
  883.  */
  884.  
  885. tosyn(voicenum,data,swap)
  886. char *data;
  887. {
  888.     int n, t;
  889.  
  890.     for ( n=0; n<Voicesize; n++ ) {
  891.         if ( swap ) {
  892.             t = VOICEBYTE(Syndata,voicenum,n);
  893.             VOICEBYTE(Syndata,voicenum,n) = data[n];
  894.             data[n] = t;
  895.         }
  896.         else
  897.             VOICEBYTE(Syndata,voicenum,n) = data[n];
  898.     }
  899. }
  900.  
  901. tolib(voicenum,data,swap)
  902. char *data;
  903. {
  904.     int n, t;
  905.     char *p = bankvoice(voicenum);
  906.  
  907.     for ( n=0; n<Voicesize; n++ ) {
  908.         if ( swap ) {
  909.             t = *p;
  910.             *p = data[n];
  911.             data[n] = t;
  912.         }
  913.         else
  914.             *p = data[n];
  915.         p++;
  916.     }
  917. }
  918.  
  919. tocurrent(data,voicenum)
  920. char *data;
  921. int voicenum;
  922. {
  923.     int n;
  924.  
  925.     for ( n=0; n<Voicesize; n++ )
  926.         Currdata[n] = VOICEBYTE(data,voicenum,n);
  927.     (*Sendedit)(Currdata);
  928. }
  929.  
  930. /*
  931.  * readsynth
  932.  *
  933.  * Read a bulk dump from the synth, with some tolerance for errors.
  934.  */
  935. readsynth(data)
  936. char *data;
  937. {
  938.     if ( Getbulk == NULL ) {
  939.         message("That synth is unable to dump anything!!");
  940.         return(1);
  941.     }
  942.     message("Trying to download data from synth...");
  943.     if ( (*Getbulk)(data) == 0 ) {
  944.         clearmess();
  945.         return(0);
  946.     }
  947.     message("Unable to read data from synth!");
  948.     sprintf(Buff,"Reason: %s",Reason);
  949.     message(Buff);
  950.     message("Perhaps connections are amiss?");
  951.     return(1);
  952. }
  953.  
  954. char *
  955. vnumtext(n)
  956. {
  957.     static char vnbuff[6];
  958.  
  959.     if ( Numof == NULL ) {
  960.         sprintf(vnbuff,"%2d",n);
  961.         return(vnbuff);
  962.     }
  963.     else
  964.         return((*Numof)(n - 1)); /* keep this 0-based */
  965. }
  966.  
  967. /*
  968.  * syntodisplay(n)
  969.  *
  970.  * Tranfer Syndata names to dialog boxes (Dxvoices) starting at n.
  971.  */
  972. syntodisplay(n)
  973. {
  974.     int k, r;
  975.  
  976.     /* for the NUMONSCREEN dialog boxes */
  977.     for ( k=0; k<NUMONSCREEN; k++ ) {
  978.         r = FIRSTROW+1+k;
  979.         windgoto(r,LEFTSIDE);
  980.         sprintf(Buff,"%-3s",vnumtext(n+k+1));
  981.         windstr(Buff);
  982.         windgoto(r,LEFTSIDE+6);
  983.         windstr("                 ");
  984.  
  985.         /* pull the name out of the Syndata */
  986.         windgoto(r,LEFTSIDE+6);
  987.         windstr((*Nameof)( & (VOICEBYTE(Syndata,n+k,0) )) );
  988.     }
  989.     windrefresh();
  990. }
  991.  
  992. /*
  993.  * libtodisplay
  994.  *
  995.  * Tranfer Libdata names to the screen, starting at voice 'firstv'.
  996.  */
  997.  
  998. libtodisplay(firstv)
  999. {
  1000.     int k, r;
  1001.  
  1002.     windgoto(FIRSTROW-1,RIGHTSIDE-1);
  1003.     sprintf(Buff,"Library Voices (Bank %d)",Libbank+1);
  1004.     windstr(Buff);
  1005.  
  1006.     /* for the NUMONSCREEN dialog boxes */
  1007.     for ( k=0; k<NUMONSCREEN; k++ ) {
  1008.         r = FIRSTROW+1+k;
  1009.         windgoto(r,RIGHTSIDE);
  1010.         sprintf(Buff,"%-3s",vnumtext(firstv+k+1));
  1011.         windstr(Buff);
  1012.         windgoto(r,RIGHTSIDE+6);
  1013.         windstr("                 ");
  1014.  
  1015.         /* pull the name out of the Libdata */
  1016.         windgoto(r,RIGHTSIDE+6);
  1017.         windstr((*Nameof)(bankvoice(firstv+k)));
  1018.     }
  1019.     windrefresh();
  1020. }
  1021.  
  1022. allnotesoff()
  1023. {
  1024.     int n;
  1025.  
  1026.     /* Go through all channels. */
  1027.     for ( n=0; n<15; n++ ) {
  1028.         sendmidi(n | 0xb0);
  1029.         sendmidi(0x7b);
  1030.         sendmidi(0x00);
  1031.     }
  1032. }
  1033.  
  1034. /*
  1035.  * Below are generic edit routines, which manage a screen display
  1036.  * showing parameter values, and let you roam around and make changes.
  1037.  * The display is managed by the contents of the P array, which
  1038.  * contains the name, screen location, min/max values, etc. of
  1039.  * each parameter.
  1040.  */
  1041.  
  1042. int Prow = 0;
  1043. int Pcol = 0;
  1044. int Parm = 0;
  1045.  
  1046. /* redraw the parameter screen */
  1047. showallparms(name)
  1048. char *name;
  1049. {
  1050.     int n;
  1051.     char *s;
  1052.  
  1053.     windclear();
  1054.  
  1055.     showname(name);
  1056.     windgoto(1,0);
  1057.     for(n=strlen(name)+6;n>0;n--)
  1058.         windputc('=');
  1059.  
  1060.     /* The L array contains arbitrary screen labels */
  1061.     for ( n=0; L[n].l_text != NULL; n++ ) {
  1062.         windgoto(L[n].l_row,L[n].l_col);
  1063.         windstr(L[n].l_text);
  1064.     }
  1065.     /* Display each parameter value, and a label if there is one. */
  1066.     for ( n=0; P[n].p_name != NULL; n++ ) {
  1067.         if ( P[n].p_flags != 0 )
  1068.             continue;
  1069.         if ( (s=P[n].p_label) != NULL )
  1070.             showstr(s,P[n].p_lrow,P[n].p_lcol,0);
  1071.         showparam(n,0);
  1072.     }
  1073.     windrefresh();
  1074. }
  1075.  
  1076. showname(name)
  1077. char *name;
  1078. {
  1079.     windgoto(0,0);
  1080.     windstr("Name:                 ");
  1081.     windgoto(0,6);
  1082.     windstr(name);
  1083. }
  1084.  
  1085. showparam(n,eras)
  1086. {
  1087.     char *p;
  1088.  
  1089.     /* The p_tovis element of the P array is a function which, given */
  1090.     /* the parameter value as an argument, returns a string which is */
  1091.     /* what should be displayed on the screen. */
  1092.     p = (*(P[n].p_tovis))(P[n].p_val);
  1093.     showstr(p,P[n].p_vrow,P[n].p_vcol,eras);
  1094. }
  1095.  
  1096. showstr(p,row,col,eras)
  1097. register char *p;
  1098. register int col;
  1099. {
  1100.     register int c;
  1101.  
  1102.     windgoto(row,col);
  1103.     while ( (c=(*p++)) != '\0' ) {
  1104.         switch(c){
  1105.         case '~':
  1106.             switch( (c=(*p++)) ) {
  1107.             case 'u': row--; goto wgoto;
  1108.             case 'd': row++; goto wgoto;
  1109.             case 'l': col--; goto wgoto;
  1110.             case 'r': col++;
  1111.                 wgoto:
  1112.                 windgoto(row,col);
  1113.                 break;
  1114.             default:
  1115.                 windputc(eras?' ':c);
  1116.                 col++;
  1117.                 break;
  1118.             }
  1119.             break;
  1120.         default:
  1121.             windputc(eras?' ':c);
  1122.             col++;
  1123.             break;
  1124.         }
  1125.     }
  1126. }
  1127.  
  1128. /* Allow roaming around and changing of parameter values. */
  1129. editdata(name,data)
  1130. char *name;
  1131. char *data;    /* vmem format */
  1132. {
  1133.     int c, n;
  1134.  
  1135.     windclear();
  1136.     windrefresh();
  1137.     /* enable all the parameters */
  1138.     for ( n=0; P[n].p_name != NULL; n++ )
  1139.         enableparm(n);
  1140.  
  1141.     /* Take the voice data and put it into P */
  1142.     (*Datain)(data);
  1143.  
  1144.     Prow = Pcol = 0;
  1145.     Changed = 0;
  1146.     Redraw = 1;
  1147.     gotoparm(CH_RIGHT);    /* Get to the first parameter */
  1148.     for ( ;; ) {
  1149.         if ( Redraw ) {
  1150.             showallparms(name);
  1151.             Redraw = 0;
  1152.         }
  1153.         windgoto(Prow,Pcol);
  1154.         windrefresh();
  1155.         c = mouseorkey();
  1156.         if ( c == MOUSE ) {
  1157.             editmouse();
  1158.             continue;
  1159.         }
  1160.         switch(c){
  1161.         case CH_RIGHT:
  1162.         case CH_UP:
  1163.         case CH_DOWN:
  1164.         case CH_LEFT:
  1165.             gotoparm(c);
  1166.             break;
  1167.         case CH_REDRAW:
  1168.             showallparms(name);
  1169.             break;
  1170.         case 'N':
  1171.             /* Allow changing of voice name */
  1172.             windgoto(0,5);
  1173.             windstr("                ");
  1174.             windgoto(0,6);
  1175.             windrefresh();
  1176.             windgets(Buff);
  1177.             if ( Buff[0]!='\0' && Buff[0]!='\n' )
  1178.                 (*Setnameof)(data,Buff);
  1179.             showname(name=(*Nameof)(data));
  1180.             Changed = 1;
  1181.             break;
  1182.  
  1183.         case CH_INC:
  1184.             adjuparm(1);
  1185.             break;
  1186.         case CH_INC2:
  1187.             adjuparm(4);
  1188.             break;
  1189.         case CH_INC3:
  1190.             adjuparm(P[Parm].p_max - P[Parm].p_min);
  1191.             break;
  1192.         case CH_DEC:
  1193.             adjuparm(-1);
  1194.             break;
  1195.         case CH_DEC2:
  1196.             adjuparm(-4);
  1197.             break;
  1198.         case CH_DEC3:
  1199.             adjuparm(P[Parm].p_min - P[Parm].p_max);
  1200.             break;
  1201. #ifdef OLDSTUFF
  1202.         case 'a':
  1203.             sendaced(data);
  1204.             playnote(0);
  1205.             break;
  1206. #endif
  1207.         case ' ':
  1208.         case '\n':
  1209. #ifndef macintosh
  1210.         case '\r':
  1211. #endif
  1212.             if ( Changed ) {
  1213.                 (*Dataout)(data);
  1214.                 (*Sendedit)(data);
  1215.             }
  1216.             playnote(0);
  1217.             break;
  1218.         case '\033':
  1219.         case '`':
  1220.             allnotesoff();
  1221.             break;
  1222.         case 'q':
  1223.         case EOF:
  1224.             if ( Changed ) {
  1225.                 (*Dataout)(data);
  1226.                 (*Sendedit)(data);
  1227.             }
  1228.             return;
  1229.         default:
  1230.             break;
  1231.         }
  1232.     }
  1233. }
  1234.  
  1235. adjuparm(incdec)
  1236. {
  1237.     int v, n;
  1238.  
  1239.     v = P[Parm].p_val + incdec;
  1240.     if ( v < (n=P[Parm].p_min) )
  1241.         v = n;
  1242.     if ( v > (n=P[Parm].p_max) )
  1243.         v = n;
  1244.     Changed = 1;
  1245.     showparam(Parm,1);    /* erase the old val */
  1246.     P[Parm].p_val = v;
  1247.     showparam(Parm,0);    /* show the new val */
  1248. }
  1249.  
  1250. editmouse()
  1251. {
  1252.     int row, col, thisparm;
  1253.  
  1254.     getmouse(&row,&col);
  1255.     thisparm = closeparm(row,col);
  1256.     if ( thisparm == Parm ) {
  1257.         if ( statmouse() > 1 )
  1258.             adjuparm(-1);    /* right button */
  1259.         else if ( statmouse() == 1 ) /* added by mab - bug fix */
  1260.             adjuparm(1);    /* left button */
  1261.     }
  1262.     else {
  1263.         Parm = thisparm;
  1264.         Prow = P[Parm].p_vrow;
  1265.         Pcol = P[Parm].p_vcol;
  1266.     }
  1267. }
  1268.  
  1269. /* closeparm - Find the closest parameter */
  1270. closeparm(row,col)
  1271. {
  1272.     register struct paraminfo *pp;
  1273.     register int n;
  1274.     int dist, mindist, minparm, dr, dc;
  1275.  
  1276.     minparm = 0;
  1277.     mindist = Rows + Cols;
  1278.     for ( n=0,pp=P; pp->p_name != NULL; n++,pp++ ) {
  1279.         if ( pp->p_flags != 0 )
  1280.             continue;
  1281.         if ( (dr=row-(pp->p_vrow)) < 0 )
  1282.             dr = -dr;
  1283.         if ( (dc=col-(pp->p_vcol)) < 0 )
  1284.             dc = -dc;
  1285.         if ( (dist=dr*dr+dc*dc) < mindist ) {
  1286.             minparm = n;
  1287.             mindist = dist;
  1288.         }
  1289.     }
  1290.     return(minparm);
  1291. }
  1292.  
  1293. /* playnote - play the 'auto' note */
  1294. playnote(i)
  1295. {
  1296.     int pitch, vol, dur, chan;
  1297.     long endtime;
  1298.  
  1299.     pitch = getval("autopitch");
  1300.     if(i == 0) { /* called from inside edit-mode */
  1301.         chan = getval("autochan");
  1302.     } else { /* called from the top level */
  1303.         chan = Channel;
  1304.     }
  1305.     vol = getval("autovol");
  1306.     dur = getval("autodur");
  1307.     endtime = milliclock() + dur * 100;
  1308.     midinote(1,chan,pitch,vol);
  1309.     while ( milliclock() < endtime )
  1310.         ;
  1311.     midinote(0,chan,pitch,vol);
  1312. }
  1313.  
  1314. /* gotoparm - search for the next parameter in the specified direction */
  1315. gotoparm(dir)
  1316. {
  1317.     int n, k, inc, pm, orig, r = Prow, c = Pcol;
  1318.  
  1319.     if ( dir==CH_LEFT || dir==CH_RIGHT ) {
  1320.         if ( dir==CH_LEFT )
  1321.             c--;
  1322.         else
  1323.             c++;
  1324.         orig = c;
  1325.         inc = 0;
  1326.         pm = -1;
  1327.         /* look up and down, alternately */
  1328.         for ( n=2*Rows; n>0; n-- ) {
  1329.             r += (pm * inc++);
  1330.             pm = -pm;
  1331.             if ( r < 0 || r >= Rows )
  1332.                 continue;
  1333.             if ( dir == CH_LEFT ) {
  1334.                 for ( c=orig; c>=0; c-- ) {
  1335.                     if ( parmat(r,c) )
  1336.                         return;
  1337.                 }
  1338.             }
  1339.             else {
  1340.                 for ( c=orig; c<Cols; c++ ) {
  1341.                     if ( parmat(r,c) )
  1342.                         return;
  1343.                 }
  1344.             }
  1345.         }
  1346.         return;
  1347.     }
  1348.     if ( dir==CH_DOWN || dir==CH_UP ) {
  1349.         if ( dir==CH_DOWN )
  1350.             r++;
  1351.         else
  1352.             r--;
  1353.         orig = c;
  1354.         while ( r >= 0 && r < Rows ) {
  1355.             /* look toward both sides at the same time */
  1356.             inc = 0;
  1357.             pm = -1;
  1358.             for ( k=2*Cols; k>0; k-- ) {
  1359.                 c += (pm * inc++);
  1360.                 pm = -pm;
  1361.                 if ( c < 0 || c >= Cols )
  1362.                     continue;
  1363.                 if ( parmat(r,c) )
  1364.                     return;
  1365.             }
  1366.             if ( dir==CH_DOWN )
  1367.                 r++;
  1368.             else
  1369.                 r--;
  1370.             c = orig;
  1371.         }
  1372.         return;
  1373.     }
  1374. }
  1375.  
  1376. /* paramat - return non-zero if a parameter value is at position r,c */
  1377. parmat(r,c)
  1378. register int r, c;
  1379. {
  1380.     register int n;
  1381.     register struct paraminfo *pp;
  1382.  
  1383.     for ( n=0,pp=P; pp->p_name != NULL; n++,pp++ ) {
  1384.         if ( pp->p_flags != 0 )
  1385.             continue;
  1386.         if ( pp->p_vrow==r && pp->p_vcol==c ) {
  1387.             Prow = r;
  1388.             Pcol = c;
  1389.             Parm = n;
  1390.             return(1);
  1391.         }
  1392.     }
  1393.     return(0);
  1394. }
  1395.  
  1396. /* parmindex - return index (in P) of a given parameter name. */
  1397. parmindex(name)
  1398. char *name;
  1399. {
  1400.     int n;
  1401.     char *s;
  1402.  
  1403.     for ( n=0; (s=P[n].p_name) != NULL; n++ ) {
  1404.         if ( strcmp(s,name) == 0 )
  1405.             return(n);
  1406.     }
  1407.     sprintf(Buff,"HEY, PARMINDEX(%s) NOT FOUND!",name);
  1408.     windstr(Buff);
  1409.     windrefresh();
  1410.     return(-1);
  1411. }
  1412.  
  1413. setval(name,v)
  1414. char *name;
  1415. {
  1416.     int n;
  1417.  
  1418.     if ( (n=parmindex(name)) < 0 )
  1419.         return;
  1420.     P[n].p_val = v;
  1421. }
  1422.  
  1423. getval(name)
  1424. char *name;
  1425. {
  1426.     int n;
  1427.  
  1428.     if ( (n=parmindex(name)) < 0 )
  1429.         return(0);
  1430.     return(P[n].p_val);
  1431. }
  1432.  
  1433. enableparm(n)
  1434. {
  1435.     if ( P[n].p_flags != 0 )
  1436.         P[n].p_flags = 0;
  1437. }
  1438.  
  1439. disableparm(n)
  1440. {
  1441.     if ( P[n].p_flags == 0 )
  1442.         P[n].p_flags = 1;
  1443. }
  1444.  
  1445. midinote(onoff,chan,pitch,vol)
  1446. {
  1447.     sendmidi( ((onoff==1)?(0x90):(0x80)) | ((chan-1)&0xf) );
  1448.     sendmidi( pitch & 0x7f );
  1449.     sendmidi( vol & 0x7f );
  1450. }
  1451.  
  1452. static char Nbuff[16];
  1453.  
  1454. char *visnum(v)
  1455. {
  1456.     sprintf(Nbuff,"%d",v);
  1457.     return(Nbuff);
  1458. }
  1459. char *visonoff(v)
  1460. {
  1461.     if ( v==0 )
  1462.         return("off");
  1463.     else
  1464.         return("on");
  1465. }
  1466.  
  1467. char *
  1468. bankvoice(voice)
  1469. {
  1470.     int offset = Libbank * Nvoices * Voicesize + voice * Voicesize;
  1471.     return(Libdata + offset);
  1472. }
  1473.